# !/usr/bin/env python3
# coding=utf8
"""
"""
import datetime
import json
from typing import Any, Type, Optional, Union, Callable, Sequence  # , Dict, List, Set, Tuple
import vnpy.tools.utility
import vnpy.trader.database
import vnpy.trader.datafeed
import vnpy_ctastrategy.backtesting
import vnpy_tdxdata.tdxdata_datafeed
from vnpy.trader.object import (
    Interval,
    Exchange,
    BarData,
    HistoryRequest,
)


def get_product_exchange_mapping() -> dict[str, Exchange]:
    """"""
    vnpy.tools.utility.get_exchange
    # 以下内容摘自 vnpy.tools.utility.get_exchange
    ########################################

    conf: dict = {
        Exchange.CFFEX: ["IC", "IF", "IH", "IM", "T", "TF", "TL", "TS"],
        Exchange.CZCE: ["AP", "CF", "CJ", "CY", "FG", "JR", "LR", "MA", "OI", "PF", "PK", "PM", "PR", "PX", "RI", "RM", "RS", "SA", "SF", "SH", "SM", "SR", "TA", "UR", "WH", "ZC"],
        Exchange.DCE: ["A", "B", "BB", "C", "CS", "EB", "EG", "FB", "I", "J", "JD", "JM", "L", "LG", "LH", "M", "P", "PG", "PP", "RR", "V", "Y"],
        Exchange.GFEX: ["LC", "PS", "SI"],
        Exchange.INE: ["BC", "EC", "LU", "NR", "SC"],
        Exchange.SHFE: ["AG", "AL", "AO", "AU", "BR", "BU", "CU", "FU", "HC", "NI", "PB", "RB", "RU", "SN", "SP", "SS", "WR", "ZN"],
    }

    cache: dict[str, Exchange] = {}

    for exchange, product_s in conf.items():
        for product in product_s:
            cache[product] = exchange

    ########################################

    return cache


def download_bar_data(date: datetime.date, interval: Interval):
    """
    下载 date~NOW 的 interval 的数据,
    """
    assert interval in (Interval.MINUTE, Interval.MINUTE05)

    database: vnpy.trader.database.BaseDatabase = vnpy.trader.database.get_database()
    datafeed: vnpy.trader.datafeed.BaseDatafeed = vnpy.trader.datafeed.get_datafeed()

    count: int = 0

    cache: dict[str, Exchange] = get_product_exchange_mapping()

    for product, exchange in cache.items():

        print(f"{datetime.datetime.now()} : {interval}, {exchange.value}.{product}, beg,")

        req: HistoryRequest = HistoryRequest(
            symbol=f"{product}L8",
            exchange=exchange,
            start=datetime.datetime.combine(date=date, time=datetime.time.min),
            end=datetime.datetime.now(),
            interval=interval,
        )

        data: list[BarData] = datafeed.query_bar_history(req=req)

        if data:
            database.save_bar_data(data)

        count += 1

        print(f"{datetime.datetime.now()} : {interval}, {exchange.value}.{product}, end, {count}/{len(cache)},")


def guess_product_one(interval: Interval, exchange: Exchange, product: str, business_day: datetime.date) -> tuple[tuple[str, str], ...]:
    """"""
    assert interval in (Interval.MINUTE, Interval.MINUTE05)

    INTERVAL_ADJUSTMENT_MAP: dict[Interval, datetime.timedelta] = {
        Interval.MINUTE05: datetime.timedelta(minutes=5),
        Interval.MINUTE: datetime.timedelta(minutes=1),
    }

    # https://docs.python.org/zh-cn/3/library/typing.html
    # 要表示一个可以是 任意 长度的元组，并且其中的所有元素都是相同类型的 T，请使用 tuple[T, ...]。

    start, end = vnpy_ctastrategy.backtesting.BacktestingEngine.fix_start_end(
        datetime.datetime.combine(date=business_day, time=datetime.time.min),
        datetime.datetime.combine(date=business_day, time=datetime.time.min),
    )

    symbol: str = f"{product}L8"
    symbol: str = vnpy_tdxdata.tdxdata_datafeed.TdxdataDatafeed.conv_symbol_4_use(exchange=exchange, symbol=symbol)

    req: HistoryRequest = HistoryRequest(
        symbol=symbol,
        exchange=exchange,
        start=start,
        end=end,
        interval=interval,
    )

    database: vnpy.trader.database.BaseDatabase = vnpy.trader.database.get_database()

    bars: list[BarData] = database.load_bar_data(
        symbol=req.symbol,
        exchange=req.exchange,
        interval=req.interval,
        start=req.start,
        end=req.end,
    )

    datetimerange_s: list[tuple[datetime.datetime, datetime.datetime]] = []

    beg: Optional[datetime.datetime] = None
    lst: Optional[datetime.datetime] = None
    for idx, bar in enumerate(bars):
        if beg is None:
            beg = bar.datetime
        lst = bar.datetime

        if idx + 1 == len(bars):  # 如果这是最后一个数据,
            datetimerange_s.append((beg, lst))
            beg = lst = None
            continue

        # 考虑到 Interval.MINUTE05 和"上午有10:15~10:30的间隔", 拍脑袋决定用10分钟做判断,
        if datetime.timedelta(minutes=10) < bars[idx + 1].datetime - bar.datetime:
            datetimerange_s.append((beg, lst))
            beg = lst = None

    for indx, item in enumerate(datetimerange_s):
        beg: datetime.datetime = item[0]
        end: datetime.datetime = item[1] + INTERVAL_ADJUSTMENT_MAP[interval]
        datetimerange_s[indx] = (beg, end)

    dest: tuple[tuple[str, str], ...] = tuple([(item[0].strftime("%H:%M"), item[1].strftime("%H:%M")) for item in datetimerange_s])

    return dest


def guess_product_multi(interval: Interval, business_day: datetime.date):
    """"""
    cache: dict[str, Exchange] = get_product_exchange_mapping()

    mapping: dict[tuple, list[str]] = {}

    for product, exchange in cache.items():
        key: tuple = guess_product_one(interval=interval, exchange=exchange, product=product, business_day=business_day)
        mapping.setdefault(key, [])
        mapping[key].append(f"{exchange.value}.{product}")
        mapping[key].sort()

    kvs: dict[str, str] = {str(key): str(val) for key, val in mapping.items()}

    sss: str = json.dumps(obj=kvs, sort_keys=True, indent=2)
    sss: str = sss.replace('"', '')

    with open(file=__file__ + ".log", mode="w", encoding="utf8") as f:
        f.write(sss)

    print(sss)


if __name__ == "__main__":
    if 0:
        # Interval.MINUTE  , total_seconds: 6492秒 => 约108分钟,
        # Interval.MINUTE05, total_seconds: 1502秒 => 约025分钟,
        for interval in [Interval.MINUTE, Interval.MINUTE05]:
            dt1 = datetime.datetime.now()
            download_bar_data(date=datetime.date(year=2019, month=1, day=1), interval=interval)
            dt2 = datetime.datetime.now()
            print(f"{interval}, total_seconds:", (dt2 - dt1).total_seconds())
    guess_product_multi(interval=Interval.MINUTE05, business_day=datetime.date(year=2025, month=3, day=21))
